package com.taxx.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * 数据压缩工具类
 * 用于将JSON数据压缩为gzip格式并进行base64编码
 */
@Slf4j
public class DataCompressionUtil {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 将对象压缩为gzip+base64格式
     *
     * @param data 要压缩的数据对象
     * @return 压缩后的base64字符串
     */
    public static String compressToGzipBase64(Object data) {
        try {
            // 将对象转换为JSON字符串
            String jsonString = objectMapper.writeValueAsString(data);
            log.debug("原始JSON数据: {}", jsonString);

            // 压缩为gzip
            byte[] gzipData = compressGzip(jsonString);
            log.debug("GZIP压缩后大小: {} bytes", gzipData.length);

            // 进行base64编码
            String base64String = Base64.getEncoder().encodeToString(gzipData);
            log.debug("Base64编码后大小: {} characters", base64String.length());

            return base64String;

        } catch (Exception e) {
            log.error("数据压缩失败", e);
            throw new RuntimeException("数据压缩失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将base64编码的gzip数据解压缩为原始字符串
     *
     * @param base64GzipData base64编码的gzip数据
     * @return 解压缩后的原始字符串
     */
    public static String decompressFromGzipBase64(String base64GzipData) {
        try {
            // Base64解码
            byte[] gzipData = Base64.getDecoder().decode(base64GzipData);
            log.debug("Base64解码后大小: {} bytes", gzipData.length);

            // GZIP解压缩
            String jsonString = decompressGzip(gzipData);
            log.debug("GZIP解压缩后数据: {}", jsonString);

            return jsonString;

        } catch (Exception e) {
            log.error("数据解压缩失败", e);
            throw new RuntimeException("数据解压缩失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将gzip数据解压缩为字符串
     *
     * @param gzipData gzip压缩的数据
     * @return 解压缩后的字符串
     */
    private static String decompressGzip(byte[] gzipData) throws IOException {
        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(gzipData);
             GZIPInputStream gzipInputStream = new GZIPInputStream(byteArrayInputStream);
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[1024];
            int len;
            while ((len = gzipInputStream.read(buffer)) > 0) {
                byteArrayOutputStream.write(buffer, 0, len);
            }

            return byteArrayOutputStream.toString(StandardCharsets.UTF_8.name());
        }
    }

    /**
     * 将JSON字符串压缩为gzip格式
     *
     * @param jsonString JSON字符串
     * @return gzip压缩后的字节数组
     */
    private static byte[] compressGzip(String jsonString) throws Exception {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream)) {

            // 写入数据到gzip流
            gzipOutputStream.write(jsonString.getBytes(StandardCharsets.UTF_8));
            gzipOutputStream.finish();

            return byteArrayOutputStream.toByteArray();
        }
    }

    /**
     * 构建完整的税务报送请求
     *
     * @param ywlx 业务类型
     * @param data 要报送的数据对象
     * @return 完整的报送请求对象
     */
    public static TaxReportRequestWrapper buildTaxReportRequest(String ywlx, Object data) {
        TaxReportRequestWrapper request = new TaxReportRequestWrapper();
        request.setYwlx(ywlx);
        request.setSjl(compressToGzipBase64(data));
        return request;
    }

    /**
     * 解析税务报送请求
     *
     * @param requestWrapper 税务报送请求包装对象
     * @param clazz 目标类类型
     * @return 解析后的对象
     */
    public static <T> T parseTaxReportRequest(TaxReportRequestWrapper requestWrapper, Class<T> clazz) {
        try {
            String decompressedData = decompressFromGzipBase64(requestWrapper.getSjl());
            return objectMapper.readValue(decompressedData, clazz);
        } catch (Exception e) {
            log.error("解析税务报送请求失败", e);
            throw new RuntimeException("解析税务报送请求失败: " + e.getMessage(), e);
        }
    }

    /**
     * 税务报送请求包装类
     */
    public static class TaxReportRequestWrapper {
        private String ywlx;
        private String sjl;

        public String getYwlx() {
            return ywlx;
        }

        public void setYwlx(String ywlx) {
            this.ywlx = ywlx;
        }

        public String getSjl() {
            return sjl;
        }

        public void setSjl(String sjl) {
            this.sjl = sjl;
        }
    }

}
